﻿using GatherSystem;
using MongoDB.Bson;
using MongoDB.Driver;
using MongoDB.Driver.Builders;
using MongoDB.Driver.GridFS;
using MongoDB.Driver.Linq;
using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
using UnityEngine;
using UnityEngine.SceneManagement;
using UnityEngine.UI;
using System.Runtime.InteropServices;
using System.IO;

namespace GatherSystem
{

    public class GatherMain : MonoBehaviour
    {
        private string IP = "10.11.176.109";
        private string dbname = "GatherSystem";
        private string collectionName= "gameData";
        private float updateInterval = 1f;

        bool senceOn = false;
        public static GatherMain instance
        {
            get { return m_instance; }
        }

        static GatherMain m_instance;
        /// <summary>
        /// 累加值
        /// </summary>
        private float accum = 0;

        /// <summary>
        /// 帧频
        /// </summary>
        private int frames = 0;

        /// <summary>
        /// 计时数值
        /// </summary>
        private float timeLeft;


        /// <summary>
        /// FPS显示字符
        /// </summary>
        private double fps;
        private static int targetFrame;
        ArrayList fpsArray;

        ArrayList pssArray;

        ArrayList temperatureArray;

        ArrayList vssArray;

        ArrayList batteryArray;

        ArrayList currentArray;

        string m_sceneName;

        string sceneName;

        private string deviceName;

        private string gatherTime;

        private double totalPower;


        //   安卓SDK

        private MiniPerf m_MiniPerfSDK;

        Dictionary<string, int> senceCount = new Dictionary<string, int>();

        Thread uploadThread;

        private GameObject uploadButton;
        private Text buttonText;
        private Text recordTimeText;
        private Text dataText;

        private StringBuilder gatherInfo;

        float startTime;

        // Start is called before the first frame update
        void Start()
        {
            string path = default(string);
            InitBaseData();
            try
            {
                path = Application.dataPath + "/StreamingAsset";
                string[] contents = File.ReadAllLines( path + "/IP.ini", Encoding.Default);
                IP = contents[0];
                dbname = contents[1];
                collectionName = contents[2];
                Debug.Log("找到路径");
            } 
            catch
            {
                
                Debug.Log("没有找到路径");
            }

            //加载UI
            uploadButton = GameObject.Find("upload");
            uploadButton.GetComponent<Button>().onClick.AddListener(UploadEvent);
            buttonText = uploadButton.GetComponentsInChildren<Text>()[0];
            recordTimeText = uploadButton.GetComponentsInChildren<Text>()[1];
            dataText = GameObject.Find("GatherInfo").GetComponent<Text>();
            dataText.text = "CurrentStatus:Not Started";

            recordTimeText.enabled = false;

            if (gatherInfo == null)
                gatherInfo = new StringBuilder();

            Debug.Log("lyh start");
#if UNITY_ANDROID && !UNITY_EDITOR
            m_instance = this;
            m_MiniPerfSDK = new MiniPerf();
            m_MiniPerfSDK.init();
#endif
            Debug.Log("lyh Miniperf");
            

        }

        void UploadEvent()
        {
            Debug.Log("lyh upload click");
            if (!senceOn)
            {
                startTime = Time.time;
                buttonText.text = "| |";
                recordTimeText.enabled = true;

                //清除上次记录的数据
                fpsArray.Clear();
                pssArray.Clear();
                temperatureArray.Clear();
                vssArray.Clear();
                batteryArray.Clear();
                jankCount = 0;
                bigJankCount = 0;

                senceOn = true;
            }
            else
            {
                gatherTime = $"{DateTime.Now:yyy - MM - dd HH: mm: ss}";
                buttonText.text = " ►";
                recordTimeText.text = "0:0";
                recordTimeText.enabled = false;

                dataText.text = gatherInfo.ToString() + "CurrentStatus:Uploading...";

                uploadThread = new Thread(UploadGatherData);
                uploadThread.Start();
              
                senceOn = false;
            }
             
        }


        void InitBaseData()
        {
            //数组初始化
            fpsArray = new ArrayList();
            pssArray = new ArrayList();
            temperatureArray = new ArrayList();
            vssArray = new ArrayList();
            batteryArray = new ArrayList();
            currentArray = new ArrayList();

            //基本参数值初始化
            if (Application.targetFrameRate == -1) Application.targetFrameRate = 60;
            targetFrame = Application.targetFrameRate;

            deviceName = SystemInfo.deviceName;
            sceneName = SceneManager.GetActiveScene().name;
#if UNITY_ANDROID && !UNITY_EDITOR
            totalPower = Power.capacity;
#endif

        }

        //System.Timers.Timer t;
        bool uploadFlag = false;
        
        public void UploadGatherData()
        {
            var document = new BsonDocument{
                {"caseID", "DefaultGame-"+(DateTime.Now.ToUniversalTime().Ticks - 621355968000000000) / 10000000},
                {"deviceName",deviceName},
                {"sceneName",sceneName},
                {"gatherTime",gatherTime},
                {"totalPower",totalPower},
                {"jank",jankCount},
                {"bigJank",bigJankCount},
                {"fps",new BsonArray(fpsArray)},
                {"fps-min-avg-max",new BsonArray(getComputedData(fpsArray))},
                {"memory usage",new BsonArray(pssArray)},
                {"memory-min-avg-max",new BsonArray(getComputedData(pssArray))},
                {"temperature",new BsonArray(temperatureArray)},
                {"temperature-min-avg-max",new BsonArray(getComputedData(temperatureArray))},
                {"vmSize",new BsonArray(vssArray)},
                {"vmSize-min-avg-max",new BsonArray(getComputedData(vssArray))},
                {"battery",new BsonArray(batteryArray)},
                {"battery-min-avg-max",new BsonArray(getComputedData(batteryArray))},
                //{"current",new BsonArray(currentArray)}
            };

            var client = new MongoClient("mongodb://" + IP);
            var server = client.GetServer();
            var database = server.GetDatabase(dbname); //数据库名称
            var collection = database.GetCollection<BsonDocument>(collectionName);//连接的表名
            collection.Insert(document);

            Debug.Log("lyh uploaddataOK");

            uploadFlag = true;

            uploadThread.Abort();

            ////ResourceRealTimeRecord.TimerOpen();//是否执行System.Timers.Timer.Elapsed事件

            //t = new System.Timers.Timer(1000);//实例化Timer类，设置间隔时间为100毫秒；

            //t.Elapsed += new System.Timers.ElapsedEventHandler(UploadGatherData);//到达时间的时候执行事件；

            //t.AutoReset = true;//设置是执行一次（false）还是一直执行(true)；

            //t.Enabled = true;//是否执行System.Timers.Timer.Elapsed事件

        }
        //public void UploadGatherData(object source, System.Timers.ElapsedEventArgs e)
        //{
           
        //}
        double[] getComputedData(ArrayList arrayList)
        {
            double[] array = new double[arrayList.Count];
            for(int i = 0; i < arrayList.Count; i++)
            {
                array[i] = (double)arrayList[i];
            }
            
            if (array.Length == 0) return null;
            Debug.Log("lyh array:" + array[0]);
            Debug.Log("lyh double:" + array[0]);
            double sum = 0.0;
            double min = array[0];
            double max = array[0];
            for(int i = 0; i < array.Length; i++)
            {
                if (array[i] < min) min = array[i];
                if (array[i] > max) max = array[i];
                sum += array[i];
            }
            double avg = Math.Round((sum / array.Length),2);
            double[] dataCollection = { min, avg, max };
            return dataCollection;
        }
        int jankCount = 0;
        int bigJankCount = 0;
        private void CalculateJank(float deltaTime)
        {           
            if (deltaTime >= 0.08333)            
            {               
                jankCount += 1;                                
                if (deltaTime >= 0.125)                    
                    bigJankCount += 1;            
            }        
        }

        private void ComputedFpsAndPower()
        {
            fps = accum / frames;             //多次后取平均值

            if (fps > targetFrame && targetFrame > -1)
                fps = targetFrame;

            fpsArray.Add(Math.Round(fps,2));
            gatherInfo.AppendLine("FPS:" + Math.Round(fps, 2)); 

            if (sumI != 0 && sumU != 0)
            {
                avgI = sumI / frames;
                avgU = sumU / frames;
                sumI = 0;
                sumU = 0;
            }
            accum = 0.0f;
            frames = 0;

        }

        double pss;
        double temp;
        double vss;
        double battery;
        float current;
        float sumI = 0.0f;
        float sumU = 0.0f;
        float avgI,avgU;
        // Update is called once per frame
        void Update()
        {
            if (senceOn)
            {
                timeLeft -= Time.deltaTime;
                accum += Time.timeScale / Time.deltaTime;  //每秒执行了多少帧
                ++frames;                                  // 帧频

                if (m_MiniPerfSDK != null)
                {
                    //电流
                    sumI += Power.electricity;
                    //电压 伏
                    sumU += Power.voltage;
                }

                    CalculateJank(Time.deltaTime);
                if (timeLeft <= 0.0)
                {
                    gatherInfo.Clear();
                    ComputedFpsAndPower();
                    //ComputedBattery();

                    if (m_MiniPerfSDK != null)
                    {
                        pss = Math.Round((float)m_MiniPerfSDK.GetPss() / 1024);
                        pssArray.Add(pss);
                        gatherInfo.AppendLine("Memory Usage:" + pss);

                        temp = m_MiniPerfSDK.GetTemperature();
                        temperatureArray.Add(temp);
                        gatherInfo.AppendLine("Temperature:" + temp);

                        int[] vssArr = { 0, 0 };
                        m_MiniPerfSDK.GetVssAndSwap(ref vssArr);
                        vss = Math.Round((float)vssArr[0] / 1024, 1);
                        vssArray.Add(vss);
                        gatherInfo.AppendLine("VmSize:" + vss);

                        //current = Math.Abs(Power.voltage) /1000;
                        //currentArray.Add(current); 
                        gatherInfo.AppendLine("Power.voltage:" + Math.Abs(avgU * 1000));
                        //gatherInfo.AppendLine("Current:" + Math.Round((float)m_MiniPerfSDK.GetCurrent() / 1000, 1));
                        gatherInfo.AppendLine("Current:" + Math.Abs(avgI));

                        //battery = Math.Round((float)m_MiniPerfSDK.GetCurrent() / 1000, 1);
                        battery = Math.Round(Math.Abs(avgI* avgU),1);
                        //Debug.Log("lyh power:" + Power.electricity+","+ Power.voltage);
                        batteryArray.Add(battery);
                        gatherInfo.AppendLine("Battery:" + battery);

                    }

                    dataText.text = gatherInfo.ToString()+"CurrentStatus:Recording...";
                    recordTimeText.text = $"{ Math.Floor((Time.time - startTime) / 60)}:{Math.Floor((Time.time - startTime) % 60)}";
                
                    //计时重置
                    timeLeft = updateInterval;
                }
            }
            if (uploadFlag)
            {
                dataText.text = gatherInfo.ToString() + "CurrentStatus:Upload OK!";
                uploadFlag = false;
            }
        }
        private void OnDestroy()
        {

            //if (t != null) t.Enabled = false;

            if (uploadThread != null) uploadThread.Abort();

            //Debug.Log("gatherThread:" + gatherThread.ThreadState);
        }
    }
}
